#include "Socket.h"

namespace phynet{
namespace net{

unsigned int Socket::s_openSockets;

Socket::Socket(const UInt i_port)
	:m_isOpen(false), m_port(INVALID_PORT)
{
	if(i_port != INVALID_PORT)
		Open(i_port);
}

bool Socket::Open(const UInt i_port)
{
	if(m_isOpen)
		return (i_port == m_port);

	if(s_openSockets == 0)
	{
		WSADATA wsaData;
		// MAKEWORD(1,1) for Winsock 1.1, MAKEWORD(2,0) for Winsock 2.0:
		if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0) 
			return false;
	}

	m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (m_socket==INVALID_SOCKET)
		return false;

	unsigned long iMode = 1;
	if(ioctlsocket(m_socket, FIONBIO, &iMode) < 0)
		return false;

	sockaddr_in sockAddr;
	sockAddr.sin_family = AF_INET;
	sockAddr.sin_addr.S_un.S_addr = INADDR_ANY;
	sockAddr.sin_port = htons(static_cast<const u_short>(i_port));

	if (bind(m_socket, (sockaddr*)(&sockAddr), sizeof(sockAddr))!=0)
		return false;

	++s_openSockets;
	m_port = i_port;
	m_isOpen = true;
	return true;
}

void Socket::Close()
{
	if(m_isOpen)
	{
		closesocket(m_socket);

		--s_openSockets;
		if(s_openSockets==0)
		{
			WSACleanup();
		}
	}
}

bool Socket::SendTo(const Address& i_addr, char* i_message, UInt i_messageSize)
{
	const unsigned int byteSent = sendto(m_socket, i_message, i_messageSize, 0, (const sockaddr*)(&i_addr.m_addr), sizeof(sockaddr));
	return (byteSent == i_messageSize);
}

bool Socket::RecvFrom(Address& o_addr, char* o_message, UInt& io_messageSize)
{
	int addrLenght;
	io_messageSize = recvfrom(m_socket, o_message, io_messageSize, 0, (sockaddr*)(&o_addr.m_addr), &addrLenght);
	return io_messageSize != 0;
}

}} //namespaces